Repository navigation
docs(skills): parent-path record-currency amounts admit no grouping; data eval for the parent-path currencyField - #33394
Conversation
…data eval for the parent-path currencyField The dashboards rule said a record-currency amount refuses sum/avg/min/max unless grouped by its code field; a master_detail child amount whose currencyField is the parent path admits no grouping on main (the engine's aggregate door and the analytics cube door both refuse it). Say so, point to objectstack-data for the declaration, and name the home field or the parent's summary as the shapes to measure. Paid for by deleting two clauses whose home is the package source. Add the objects-fields-relationships eval case for an invoice whose lines follow its currency. Claude-Session: https://claude.ai/code/session_01FEkQ5kJc3VU2HmGSE78u8t Co-Authored-By: Claude <noreply@anthropic.com>
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb Contract reviewServed-tier: Inputs read: card #32392 (body, triage, claim, os-dev-report), PR #33394 (body, three-file list, net diff against merge-base ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Findings
Nits alone end the round. Gates (the head's check-runs are the verdicts): 48 check-runs, none pending: 30 success, 18 skipped, 0 failure, cancelled or timed out. The lint families (repo and tooling, CI release and engine, docs and code guards, ESLint), the type-check families and the core test shards are all green. Nothing red. Implemented-by: VERDICT: PASS Adopted by the seat 2026-11-14T18:43Z · isolated sub-agent at CONTRACT_REVIEW_TIER · Ruling-ref: Leehom card cmsg_01TenzsRopZj4jMbvjX8uz1XFhuiZmTH8VFgMmHRmpiGAb, option A, tapped 2026-11-14T15:37Z |
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb 维护者速读
席位核对Verdict: ACCEPT, held for the maintainer · head
|
…-z8yej2 # Conflicts: # skills/objectstack-data/evals/objects-fields-relationships.json
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb Seat delta check — PR #33394 @
|
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb Correction: contract-review tierThe contract-review record(s) 6882437074 on this PR say The seat re-runs the review at |
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb Contract reviewServed-tier: Inputs read: card #32392 (body and all four comments), PR #33394 (body, three-file list, net diff against ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Findings
Nits alone end the round. Gates (the head's check-runs are the verdicts): 48 check-runs, none pending: 30 success, 18 skipped, none failed, cancelled or timed out. The lint, type-check, core test, changeset, PR-body guard and governed-surface queue guard families are green. Implemented-by: VERDICT: PASS Adopted by the seat 2026-11-15T00:30Z · isolated sub-agent at CONTRACT_REVIEW_TIER (served model verified by the seat) · Ruling-ref: Leehom card cmsg_01TenzsRopZj4jMbvjX8uz1XFhuiZmTH8VFgMmHRmpiGAb, option A, tapped 2026-11-14T15:37Z |
Requested by Leehom · project thread
Fixes #32392
domain:skills#1 · os-project-manager · session_01FEkQ5kJc3VU2HmGSE78u8t
Clause-②: no
Metadata-protocol: none
维护者速读
objectstack-ui仪表盘规则里关于currencyMode: 'record'金额的那句,补上「currencyField是父路径(如'invoice.currency_code')的金额,任何分组都不放行」,指向 objectstack-data → Field Types → Currency,并给出两种可用的单币种口径(该金额的homeAmount字段,或父对象的summary);objectstack-data的 eval 新增一例:发票明细金额跟随发票币种、lookup路径被拒。main上会被拒(引擎聚合门与分析 cube 门都拒);而父路径写法上线后 eval 里还没有一例测它。dashboards.md改 4 行删 4 行,token 6232 到 6226(付账删了同一注释里两个住在包源码的从句);回滚即还原本 PR。skills/objectstack-ui/rules/dashboards.md第 306–311 行;再看 eval 文件末尾第 18 例。git diff origin/main -- skills/,预期仪表盘规则只见那一处括号补句与两个删去的从句,eval 只多出第 18 例,其must_contain每项都在expected_output里。skills/**):请批准或合并。What changes
skills/objectstack-ui/rules/dashboards.mdlines 306–311 (a comment inside theos:checkdataset example). "AcurrencyMode: 'record'amount refusescurrency, and sum/avg/min/max unless grouped by its code field" now continues "(a parent-pathcurrencyFieldadmits none, objectstack-data → Field Types → Currency: measure itshomeAmountfield or the parent'ssummary)". The data skill's owner text is linked by name, not restated.currencyField(the per-row code column); acountnever does": the result column's wire shape, documented onAnalyticsResult.fields[].currencyFieldinpackages/spec/src/contracts/analytics-service.ts(lines 93–110) and produced atpackages/services/service-analytics/src/analytics-service.ts:3666-3693. A dashboard author writes nothing from it.currencyover adynamicfield, afixedcode against the tenant's": the measure-currency check's non-judgements, stated inpackages/services/service-analytics/src/measure-currency-coherence.ts(module header, "Not judged").skills/objectstack-data/evals/objects-fields-relationships.jsoneval 18. An invoice whose lines'amountfollows the invoice'scurrency_codethrough themaster_detail(currencyField: 'invoice.currency_code'), thelookupalternative refused, the invoicesubtotalasummarythat declares its own record currency, andERR_CURRENCY_CODE_REQUIREDfor a blank parent code.must_contain:master_detail,currencyField: 'invoice.currency_code',iso_4217_currency,summary,ERR_CURRENCY_CODE_REQUIRED;must_not_contain:currencyMode: 'fixed',Field.lookup('invoice')..changeset/32392-skills-parent-currency-path-follow-ups.md:'@objectstack/skills': patch, carrying both declaration lines.Why
The card asked for the sentence to be written to what
maindoes today ("edge 2 may have moved"). It has not moved. Read onorigin/main6538ba4:packages/objectql/src/record-currency-aggregate-door.ts:175-181: when the amount'scurrencyFieldresolves to a parent path, the door pushes a refusal before it looks atgroupByat all ("No groupBy admits it: a dotted group key is read as a column of this row, which holds no code"). The only exit is the roll-up's own recompute through that samemaster_detail(ROLLUP_AGGREGATE_OPTION), which no caller can set. The refusal text names the two remedies the new sentence names: a stored home-currency amount field, or a summary rolled up through themaster_detail.packages/objectql/src/record-currency-guards.test.ts:496-519, "an aggregate over a child amount that follows its parent is refused whatever it groups by (ADR-0144 D6, Open item 14)": ungrouped, grouped byinvoice.currency_code(string and object form) and grouped byinvoiceare each refusedINVALID_FIELD. The same describe pins the parent's roll-up as one total per currency when grouped by the parent's own code (:526-536).packages/services/service-analytics/src/cube-record-currency-door.ts:97-107admits a grouping only when a dimension's column is the code field on the same object. For a path amount the code field is the dottedinvoice.currency_code, while the dimension resolver (analytics-service.ts:4173-4198,assertRecordCurrencyGrouped) answers the last segment of a dimension'ssqland the object that segment sits on, so no dimension can match. No analytics test pins a parent-path amount; this reading is from code. The engine door underneath refuses the aggregate regardless.homeAmount:record-currency-guards.test.ts:686-703(gp_line.amountwithcurrencyField: 'invoice.currency_code'andhomeAmount), so "measure itshomeAmountfield" is reachable.Business reason (from the card): an AI author building invoice dashboards over line items reads the dashboards rule; the old sentence led to a refused dashboard, and the data skill's new parent-path rule (PR #32384) had no eval measuring it.
Acceptance notes
ui/scripts/check-skill-eval-tokens.mjs(check:skill-eval-tokens) walks onlyskills/objectui/evals/*.json(its--listnames ten files, none underskills/objectstack-data/), and no other script readsskills/objectstack-*/evals/. The README's shape was checked with a one-off script over the whole file: eval 18 is clean (everymust_containliteral inexpected_output, nomust_not_containliteral in it), and each of itsmust_containliterals occurs in the data bundle's markdown (1 to 41 occurrences).type: 'select',type: 'state_machine'), eval 12 (type: 'summary',type: 'formula') and eval 14 (label: '公司名称',value: 'active') carrymust_containliterals absent from theirexpected_output. Noted, not filed: no gate reads this bundle's evals.cube-record-currency-door.ts:109-125). Unmeasured through a public door here; the engine door's own message names the right remedies.Verification
Head
d57adb94(merge oforigin/main3968a57 after #33427 took eval 17; ours renumbered to 18), first measured on527f63efover base 6538ba4; derived gates rerun ond57adb94: 42 exit 0, the same 2 NOT MEASURED.Line and token budget (skills/**)
skills/**: +23 / -4.skills/objectstack-ui/rules/dashboards.md: 474 to 474 lines, 24926 to 24902 bytes; token ratchet 6232 to 6226 (ceiling 6232, headroom 6). The first two wordings measured +19 and +13 over; the sentence was shortened and the two package-homed clauses deleted; no ceiling moved, no re-wrap counted as payment.skills/objectstack-data/evals/objects-fields-relationships.json: 296 to 315 lines, 4463 to 4834 tokens (eval fixture, measured, not ratcheted).skills/*/SKILL.md: 4602 to 4602 lines (no SKILL.md touched). Bundle total (whole shipped tree): 244310 to 244675 tokens (base computed from the two per-file deltas, -6 and +371).node scripts/pm/check-skill-line-ratchet.mjs: exit 0.node scripts/check-skills-token-ratchet.mjs: exit 0.Derived gates: 44 derived, 42 run green, 2 NOT MEASURED
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 44 families for the three paths. Each was run with its exit code captured before any pipe, after building@objectstack/formulaand@objectstack/lintunder the verify lock (VERDICT command-exit 0, 90s):check-adr-0087-registration(scan and--self-test),check-changeset-no-major,check-empty-changeset(scan and--self-test),check-skills-token-ratchet(scan and--self-test),@objectstack/lint check:doc-formula-expressions,check:doc-authoring,check:nul-bytes,check:pm-governed-merges,check:published-files,check:skill-compatibility,check:skill-frame-sync,check:skill-identifier-liveness,check:skill-links,check:dts-closure,check:sourcemap-no-sources-content.dist/):check:dual-build-cjs-loads,check:lean-entry-closure. No package source is touched; CI builds and runs them.--ranreconciliation: "44 derived famil(ies) accounted for — 42 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)".pnpm --filter @objectstack/spec check:skill-examplesexit 0 after building the@objectstack/client-reactclosure under the verify lock (VERDICT command-exit 0, 195s): "344 prose examples type-check across 3 surface(s)". That covers the editedos:checkblock.Tier and governed readings
dispatch-gates --tier: MANDATORY contract-review tier, bothskills/**paths under clause ① (the published catalog); no one-line exit for this surface.node scripts/pm/check-governed-merges.mjs --branch claude/project-thread-z8yej2: exit 3, GOVERNED, landing tier H (人合). 2 of 3 paths hit the register (skills/**x2); the changeset is not on it. Size +33 / -4, under the 3000 threshold.🤖 Generated with Claude Code
https://claude.ai/code/session_01FEkQ5kJc3VU2HmGSE78u8t